package com.yik.countforcockpit.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yik.countforcockpit.entity.Metric;
import com.yik.countforcockpit.entity.MetricDTO;
import com.yik.countforcockpit.mapper.MetricMapper;
import com.yik.countforcockpit.utils.FormulaCalculateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import static com.yik.countforcockpit.utils.FormulaParserUtils.parseFormula;

@Service
@Slf4j
public class MetricService {

    @Autowired
    private MetricValueService metricValueService;

    // 定义匹配变量名的正则表达式
    private static final Pattern VARIABLE_PATTERN = Pattern.compile("[a-zA-Z_][a-zA-Z0-9_]*");

    private final MetricMapper metricMapper;

    public MetricService(MetricMapper metricMapper) {
        this.metricMapper = metricMapper;
    }

    public List<MetricDTO> getAllMetrics() {
        List<Metric> metrics = metricMapper.selectList(null);
        return convertMetricsToDTOs(metrics);
    }


    public Double calculateMetric(MetricDTO metricDTO) {
        String formula = metricDTO.getMetricCalculationFormula();
        log.info("Original formula:{} " , formula);
        // 1. 公式合法性校验
        if (!StringUtils.hasText(formula)) {
            throw new IllegalArgumentException("计算公式为空");
        }
        Map<String, Double> paramValues = new HashMap<>();
        List<String> paramDetails = metricDTO.getParamDetails();
        if (paramDetails != null) {
            for (String paramName : paramDetails) {
                MetricDTO paramMetric = getMetricDTOByName(paramName);
                if (paramMetric == null) {
                    throw new IllegalArgumentException("缺少参数指标: " + paramName);
                }
                double paramValue = handleMetric(paramMetric);
                paramValues.put(paramName, paramValue);
            }
        }
        // 3. 执行计算
        double result = FormulaCalculateUtils.calculate(formula, paramValues);
        // 4. 结果格式化（保留2位小数）
        return Double.parseDouble(String.format("%.2f", result));
    }

    private MetricDTO getMetricDTOByName(String metricName) {
        List<Metric> metrics = metricMapper.selectList(
                new LambdaQueryWrapper<Metric>().eq(Metric::getMetricName, metricName));
        List<MetricDTO> metricDTOS = convertMetricsToDTOs(metrics);
        return metrics.isEmpty() ? null : metricDTOS.get(0);
    }


    public double handleMetric(MetricDTO metricDTO) {
        double value = 0.0;
        // 1.原子指标
        if ("原子指标".equals(metricDTO.getMetricAttribute())) {
            value = metricValueService.getMetricValue(metricDTO.getMetricName());
            log.info("原子指标 {} 的值: {}", metricDTO.getMetricName(), value);
        } else {
            // 2.计算指标
            try {
              value = calculateMetric(metricDTO);
                log.info("计算指标 {} 计算结果: {}", metricDTO.getMetricName(), value);
            } catch (IllegalArgumentException e) {
                log.error("计算指标 {} 计算失败: {}", metricDTO.getMetricName(), e.getMessage());
            }
        }
        return value;
    }


    private List<MetricDTO> convertMetricsToDTOs(List<Metric> metrics) {
        List<MetricDTO> dtoList = new ArrayList<>();
        for (Metric metric : metrics) {
            MetricDTO dto = new MetricDTO();
            dto.setId(metric.getId());
            dto.setMetricName(metric.getMetricName());
            dto.setMetricAttribute(metric.getMetricAttribute());
            dto.setMetricDataFormat(metric.getMetricDataFormat());
            dto.setUnit(metric.getUnit());
            dto.setMetricCalculationFormula(metric.getMetricCalculationFormula());

            for (Object o : parseFormula(dto.getMetricCalculationFormula())) {
                if (o instanceof ArrayList<?>) {
                    dto.setParamDetails((List<String>) o);
                } else if (o instanceof Integer) {
                    dto.setParamCount((Integer) o);
                }
            }
            dtoList.add(dto);
        }
        return dtoList;
    }

}
